﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Diagnostics;
using Timer = System.Timers.Timer;
using System.Collections;

namespace GTA.Common.Controls
{
    /// <summary>
    /// CPU、RAM监控图
    /// </summary>
    public class MonitorChart : Control
    {
        /// <summary>
        /// 监控数据
        /// </summary>
        protected class SysInfo
        {
            public float CpuUsage { get; set; }

            public float RamUsage { get; set; }
        }

        /// <summary>
        /// 背景单元格颜色
        /// </summary>
        public virtual Color BackGridColor { get; set; }
        /// <summary>
        /// cpu曲线颜色
        /// </summary>
        public virtual Color CpuColor { get; set; }
        /// <summary>
        /// 内存曲线颜色
        /// </summary>
        public virtual Color RamColor { get; set; }
        /// <summary>
        /// 曲线跳格长度
        /// </summary>
        protected virtual int TickWidth { get; set; }

        private int _interval;
        /// <summary>
        /// 时间间隔
        /// </summary>
        public virtual int Interval
        {
            get
            {
                return _interval;
            }
            set
            {
                _interval = value;
                if (_timer != null)
                {
                    _timer.Interval = value;
                }
            }
        }

        protected List<SysInfo> Datas { get; private set; }

        private PerformanceCounter _cpu = new PerformanceCounter("Process", "% Processor Time");
        private Process _currentProc;
        private Timer _timer;

        public MonitorChart()
        {
            Datas = new List<SysInfo>();
            this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);

            this.BackColor = Color.Black;
            this.BackGridColor = Color.Green;
            this.CpuColor = Color.Lime;
            this.RamColor = Color.Orange;
            this.Font = new Font("Verdana", 12, FontStyle.Bold, GraphicsUnit.Pixel);
            this.TickWidth = 2;
            this.Interval = 1000;

            _currentProc = Process.GetCurrentProcess();
            _cpu.InstanceName = _currentProc.ProcessName;

            _timer = new Timer(this.Interval);
            _timer.AutoReset = true;
            _timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
            _timer.Start();
        }

        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            SysInfo info = new SysInfo();
            info.CpuUsage = _cpu.NextValue();
            _currentProc.Refresh();
            info.RamUsage = (_currentProc.PrivateMemorySize64 + _currentProc.PagedMemorySize64) / 1024;
            lock (
                ((ICollection)this.Datas).SyncRoot)
            {
                this.Datas.Add(info);
            }
            this.Invalidate();
        }

        #region 背景

        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            base.OnPaintBackground(pevent);
            DrawBackgroundGrid(pevent.Graphics);
        }

        /// <summary>
        /// 绘制背景单元格
        /// </summary>
        private void DrawBackgroundGrid(Graphics g)
        {
            const int width = 12, height = 12;
            Pen pen = new Pen(BackGridColor);
            for (int i = 0; i < this.Width; i += width)
            {
                g.DrawLine(pen, i, 0, i, this.Height);
            }
            for (int i = 0; i < this.Height; i += height)
            {
                g.DrawLine(pen, 0, i, this.Width, i);
            }
        }

        #endregion

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            if (Datas.Count < 2)
            {
                return;
            }
            lock (
                ((ICollection)Datas).SyncRoot)
            {
                int count = this.Width / this.TickWidth;
                if (Datas.Count > count)
                {
                    Datas.RemoveRange(0, Datas.Count - count);
                }

                float maxCpu = 0F, maxRam = 0F;
                foreach (SysInfo item in Datas)
                {
                    if (item.CpuUsage > maxCpu)
                    {
                        maxCpu = item.CpuUsage;
                    }
                    if (item.RamUsage > maxRam)
                    {
                        maxRam = item.RamUsage;
                    }
                }

                float cpuFactor = maxCpu == 0 ? 0.1F : this.Height / maxCpu * 0.7F;
                float ramFactor = maxRam == 0 ? 0.1F : this.Height / maxRam * 0.7F;

                PointF[] cpuPoints = new PointF[Datas.Count];
                PointF[] ramPoints = new PointF[Datas.Count];

                for (int i = 0, len = Datas.Count; i < len; i++)
                {
                    PointF cpuP = new PointF();
                    cpuP.X = i * this.TickWidth;
                    cpuP.Y = this.Height - (Datas[i].CpuUsage * cpuFactor) - 10;
                    cpuPoints[i] = cpuP;

                    PointF ramP = new PointF();
                    ramP.X = i * this.TickWidth;
                    ramP.Y = this.Height - (Datas[i].RamUsage * ramFactor) - 10;
                    ramPoints[i] = ramP;
                }
                Pen cpuPen = new Pen(this.CpuColor, 1.2F);
                Pen ramPen = new Pen(this.RamColor, 1.2F);

                e.Graphics.DrawLines(cpuPen, cpuPoints);
                e.Graphics.DrawLines(ramPen, ramPoints);
            }

            SysInfo last = this.Datas[this.Datas.Count - 1];
            e.Graphics.DrawString(
                string.Format("CPU USE:{0:F2}%", last.CpuUsage),
                this.Font,
                new SolidBrush(this.CpuColor),
                0,
                0);
            e.Graphics.DrawString(
                string.Format("RAM USE:{0:#,#} KB", last.RamUsage),
                this.Font,
                new SolidBrush(this.RamColor),
                0,
                20);
        }

    }
}
